package com.hyacinth.seckill.repository;

import com.hyacinth.utils.ArrayUtils;
import com.hyacinth.utils.map.MapUtil;
import com.hyacinth.wapper.PageCond;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * 基础持久化类
 */
@Slf4j
public class BaseRepositoryImpl<T extends Serializable, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {

    private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());

    @PersistenceContext
    private EntityManager entityManager;


    public BaseRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    @Override
    public List<T> query(String hql) {
        Query query = entityManager.createQuery(hql);
        return query.getResultList();
    }

    @Override
    public List<T> query(Class<T> tClass) {
        return query("from " + tClass.getSimpleName());
    }

    @Override
    public List<T> query(String hql, int maxCount) {
        return entityManager.createQuery(hql).setMaxResults(maxCount).getResultList();
    }

    @Override
    public List<T> query(String hql, Object[] paramValues) {
        Query query = entityManager.createQuery(hql);
        if (ArrayUtils.isNotEmpty(paramValues)) {
            for (int i = 0; i < paramValues.length; i++) {
                query.setParameter(i, paramValues[i]);
            }
        }
        return query.getResultList();
    }

    @Override
    public List<T> query(String hql, Map<String, Object> paramMap) {
        Query query = getQueryByHql(hql, paramMap);
        return query.getResultList();
    }

    @Override
    public long queryForCount(String hql, Map<String, Object> paramMap) {
        long count = 0;
        // 查询总条数
        Query query = getQueryByHql(hql, paramMap);
        List list = query.getResultList();
        if (CollectionUtils.isNotEmpty(list)) {
            count = Long.parseLong(String.valueOf(list.get(0)));
        }
        LOGGER.debug("hql : " + hql + ",count : " + count);
        return count;
    }

    @Override
    public List<T> queryWithPage(String hql, int begin, int fetchSize) {
        Query query = entityManager.createQuery(hql);
        query.setFirstResult(begin);
        query.setMaxResults(fetchSize);
        return query.getResultList();
    }

    @Override
    public List<T> queryWithPage(String hql, Map<String, Object> paramMap, PageCond page) {
        if (page == null) {
            return query(hql, paramMap);
        } else {  // 如果分页参数不为空
            // 查询总条数
            long count = queryForCount(hql, paramMap);
            if (count > 0) {
                page.setCount(count);

                Query query = entityManager.createQuery(hql);
                if (MapUtil.isNotEmpty(paramMap)) {
                    for (String key : paramMap.keySet()) {
                        query.setParameter(key, paramMap.get(key));
                    }
                }
                query.setFirstResult(page.getCurrentPage() * page.getLength());
                query.setMaxResults(page.getLength());
                return query.getResultList();
            }
            return null;
        }
    }

    @Override
    public List<Long> queryIds(String sql) {
        List<Long> resultList = new ArrayList<>();
        try {
            Query nativeQuery = entityManager.createNativeQuery(sql);
            resultList = nativeQuery.getResultList();
        } catch (Exception e) {
            log.error("执行SQL查询异常！sql = {}", sql);
        }
        return resultList;
    }

    @Override
    public long querySQLForCount(String sql) {
        long count = 0;
        // 查询总条数
        Query query = entityManager.createNativeQuery(sql);
        List list = query.getResultList();
        if (CollectionUtils.isNotEmpty(list)) {
            count = Long.parseLong(String.valueOf(list.get(0)));
        }
        LOGGER.debug("sql : " + sql + ",count : " + count);
        return count;
    }

    @Override
    public Object sumWithSql(String sql) {
        Query query = entityManager.createNativeQuery(sql);
        List list = query.getResultList();
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public List<Object[]> queryWithSQL(String sql) {
        return entityManager.createNativeQuery(sql).getResultList();
    }

    @Override
    public List<T> queryWithSQL(String sql, Class<T> clazz) {
        return entityManager.createNativeQuery(sql, clazz).getResultList();
    }

    @Override
    public List<T> queryWithSQLAndPage(String sql, Class<T> clazz, PageCond page) {
        Query query = entityManager.createNativeQuery(sql, clazz);
        if (page != null) {
            query.setFirstResult(page.getCurrentPage() * page.getLength());
            query.setMaxResults(page.getLength());
        }
        return query.getResultList();
    }

    @Override
    public List<Object[]> queryWithSQLOfBatch(String sql, int beginCount, int batchCount) {
        Query query = entityManager.createNativeQuery(sql);
        query.setFirstResult(beginCount);
        query.setMaxResults(batchCount);
        return query.getResultList();
    }

    @Override
    public List<Map<String, Object>> queryMapWithSQLOfBatch(String sql, int beginCount, int batchCount) {
        Query query = entityManager.createNativeQuery(sql, Map.class);
        query.setFirstResult(beginCount);
        query.setMaxResults(batchCount);
        return query.getResultList();
    }


    @Override
    public int excuteBySql(String sql) {
        Query query = entityManager.createNativeQuery(sql);
        return query.executeUpdate();
    }

    @Transactional
    public void batchInsert(List listA) {
        int size = listA.size();
        for (int i = 0; i < size; i++) {
            entityManager.persist(listA.get(i));
            if (i % 1000 == 0) {
                entityManager.flush();
                entityManager.clear();
            }
        }
    }

    private Query getQueryByHql(String hql, Map<String, Object> paramMap) {
        Query query = entityManager.createQuery(hql);
        if (MapUtil.isNotEmpty(paramMap)) {
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                query.setParameter(entry.getKey(), entry.getValue());
            }
        }
        return query;
    }
}
